package com.hp.fremarker.core;

import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 *
 * 类扫描器
 *
 * @author dongxing
 **/
public class ClassScanner {

    /**
     * 扫描类
     *
     * @param packageName   包名
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static List<Class<?>> scanClasses(String packageName) throws IOException, ClassNotFoundException {
        //扫描到的类
        List<Class<?>> classes = new ArrayList<>();
        //包名转换为文件路径
        String path = packageName.replace(".", "/");
        // 获取类加载器
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // 获取资源
        Enumeration<URL> resources = classLoader.getResources(path);

        while (resources.hasMoreElements()) {

            URL resource = resources.nextElement();
            // 如果资源类型为jar包
            if (resource.getProtocol().contains("jar")) {
                JarURLConnection jarURLConnection = (JarURLConnection) resource.openConnection();
                // jar包的绝对路径
                String jarFilePath = jarURLConnection.getJarFile().getName();
                //通过jar包的路径获取jar包下的所有的类
                classes.addAll(getClassFromJar(jarFilePath, path));
            }else {
                // todo 待解决其他类型的文件
            }
        }
        return classes;

    }

    /**
     *
     * 通过jar包的路径获取jar包下的所有的类
     *
     * @param jarFilePath   jar包的路径
     * @param path          所需要获取的类的路径
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private static List<Class<?>> getClassFromJar(String jarFilePath, String path) throws IOException, ClassNotFoundException {

        List<Class<?>> list = new ArrayList<>();
        // 获取jarFile的实例
        JarFile jarFile = new JarFile(jarFilePath);

        // 获取jarFile的所有的entry
        Enumeration<JarEntry> jarEntrys = jarFile.entries();

        while (jarEntrys.hasMoreElements()) {
            JarEntry jarEntry = jarEntrys.nextElement();

            // 获取的类文件的名字，比如com/hp/test/Test.class
            String name = jarEntry.getName();
            // 取出我们所需要的类的文件路径
            if (name.startsWith(path) && name.endsWith(".class")) {
                String classFullName = name.replace("/", ".").substring(0, name.length() - 6);
                list.add(Class.forName(classFullName));
            }
        }
        return list;
    }
}
